{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 1. 自定义日志\n",
    "在Django中，我们是**把有关logging的配置写到settings里面**。相应的配置及解释如下（仅供参考）。\n",
    "\n",
    "mail_admins将信息通过邮件发送给管理员。\n",
    "\n",
    "这里邮件的功能非常棒！并不是一个纯文本信息，而是一个html文件，和我们在浏览器看到的错误页面一模一样！要正常使用邮件功能需要像我一样配置一下上面的邮件发件人信息。我是直接去网易申请了一个邮箱。要格外注意三点：\n",
    "- 1.一定要去邮件服务商开启SMTP服务；\n",
    "- 2.不同的邮件服务商可能有一些特殊的设置，比如网易，会给你一个客户端授权码，这个才是密码，而不是网页的登录密码。\n",
    "- 3 注意服务商有没有对发信频率的限制。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    " ```py\n",
    "\n",
    "# 管理员邮箱\n",
    "ADMINS = (\n",
    "    ('laixintao', '*******@163.com'),\n",
    ")\n",
    "\n",
    "# 非空链接，却发生404错误，发送通知MANAGERS\n",
    "SEND_BROKEN_LINK_EMAILS = True\n",
    "MANAGERS = ADMINS\n",
    "\n",
    "# Email设置\n",
    "EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'\n",
    "EMAIL_HOST = 'smtp.163.com'  # QQ邮箱SMTP服务器(邮箱需要开通SMTP服务)\n",
    "EMAIL_PORT = 25  # QQ邮箱SMTP服务端口\n",
    "EMAIL_HOST_USER = '**********@163.com'  # 我的邮箱帐号\n",
    "EMAIL_HOST_PASSWORD = '**************'  # 授权码\n",
    "EMAIL_SUBJECT_PREFIX = 'website'  # 为邮件标题的前缀,默认是'[django]'\n",
    "EMAIL_USE_TLS = True  # 开启安全链接\n",
    "DEFAULT_FROM_EMAIL = SERVER_EMAIL = EMAIL_HOST_USER  # 设置发件人\n",
    "\n",
    "# logging日志配置\n",
    "LOGGING = {\n",
    "    'version': 1,\n",
    "    'disable_existing_loggers': False,\n",
    "    'formatters': {  # 日志格式\n",
    "        'standard': {  # 标准\n",
    "            'format': '%(asctime)s [%(threadName)s:%(thread)d] [%(name)s:%(lineno)d] [%(module)s:%(funcName)s] [%(levelname)s]- %(message)s'}\n",
    "    },\n",
    "        'simple': { # 简单\n",
    "            'format': '[%(levelname)s][%(asctime)s][%(filename)s:%(lineno)d]%(message)s'\n",
    "        },\n",
    "    'filters': {  # 过滤器\n",
    "        'require_debug_false': {\n",
    "            '()': 'django.utils.log.RequireDebugFalse',\n",
    "        }\n",
    "    },\n",
    "    'handlers': {  # 处理器\n",
    "        'null': {\n",
    "            'level': 'DEBUG',\n",
    "            'class': 'logging.NullHandler',\n",
    "        },\n",
    "        'mail_admins': {  # 发送邮件通知管理员\n",
    "            'level': 'ERROR',\n",
    "            'class': 'django.utils.log.AdminEmailHandler',\n",
    "            'filters': ['require_debug_false'],  # 仅当 DEBUG = False 时才发送邮件\n",
    "            'include_html': True,\n",
    "        },\n",
    "        'debug': {  # 记录到日志文件(需要创建对应的目录，否则会出错)\n",
    "            'level': 'DEBUG',\n",
    "            'class': 'logging.handlers.RotatingFileHandler',\n",
    "            'filename': os.path.join(BASE_DIR, \"log\", 'debug.log'),  # 日志输出文件\n",
    "            'maxBytes': 1024 * 1024 * 10,  # 文件大小 10M\n",
    "            'backupCount': 5,  # 备份份数\n",
    "            'formatter': 'simple',  # 使用哪种formatters日志格式\n",
    "        },\n",
    "        'console': {  # 输出到控制台\n",
    "            'level': 'DEBUG',\n",
    "            'class': 'logging.StreamHandler',\n",
    "            'formatter': 'standard',\n",
    "        },\n",
    "    },\n",
    "    'loggers': {  # logging管理器\n",
    "        'django': {\n",
    "            'handlers': ['console'],\n",
    "            'level': 'DEBUG',\n",
    "            'propagate': False  # 向不向更高级别的logger传递\n",
    "        },\n",
    "        'django.request': {\n",
    "            'handlers': ['debug', 'mail_admins'],\n",
    "            'level': 'ERROR',\n",
    "            'propagate': True,\n",
    "        },\n",
    "        # 对于不在 ALLOWED_HOSTS 中的请求不发送报错邮件\n",
    "        'django.security.DisallowedHost': {\n",
    "            'handlers': ['null'],\n",
    "            'propagate': False,\n",
    "        },\n",
    "    },\n",
    "    \"root\": {\"level\": \"INFO\", \"handlers\": [\"console\"]},\n",
    "}\n",
    "\n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 2. Django 内置日志\n",
    "\n",
    "当服务器500错误的时候，普通日志只会记录一行500的request信息，并不会记录详细的报错定位\n",
    "\n",
    ">[ERROR] 2019-06-12 15:07:03,597 \"GET /api/v1/test/ HTTP/1.1\" 500 74196\n",
    "\n",
    "1. 需要添加一个在日志中记录详细错误信息的middleware\n",
    "\n",
    "```py\n",
    "# -*- coding: UTF-8 -*-\n",
    "import logging\n",
    " \n",
    "logger = logging.getLogger('default')\n",
    " \n",
    " \n",
    "class ExceptionLoggingMiddleware(object):\n",
    "  def process_exception(self, request, exception):\n",
    "    import traceback\n",
    "    logger.error(traceback.format_exc())\n",
    "```\n",
    "\n",
    "2. 将此中间件添加到settings的MIDDLEWARE_CLASSES中\n",
    "\n",
    "```py\n",
    "MIDDLEWARE_CLASSES = (\n",
    "    'utils.my_middleware.ExceptionLoggingMiddleware',\n",
    ")\n",
    "```\n",
    "\n",
    "3. 使用Django logger\n",
    "\n",
    "```py\n",
    "'loggers': {\n",
    "  'django': {\n",
    "    'handlers': ['file', 'console'],\n",
    "    'level': 'INFO'\n",
    "  },\n",
    "```\n",
    "\n",
    "4. 最后，不要忘了给日志的路径响应的权限。比如Apache2服务器，就需要给www-data写权限：\n",
    "\n",
    "```sh\n",
    "sudo chown -R [yourname]:www-data [log]\n",
    "sudo chmod -R g+s [log]\n",
    "```"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.3"
  },
  "toc": {
   "base_numbering": 1,
   "nav_menu": {},
   "number_sections": true,
   "sideBar": true,
   "skip_h1_title": false,
   "title_cell": "Table of Contents",
   "title_sidebar": "Contents",
   "toc_cell": false,
   "toc_position": {
    "height": "calc(100% - 180px)",
    "left": "10px",
    "top": "150px",
    "width": "207.6px"
   },
   "toc_section_display": true,
   "toc_window_display": true
  },
  "varInspector": {
   "cols": {
    "lenName": 16,
    "lenType": 16,
    "lenVar": 40
   },
   "kernels_config": {
    "python": {
     "delete_cmd_postfix": "",
     "delete_cmd_prefix": "del ",
     "library": "var_list.py",
     "varRefreshCmd": "print(var_dic_list())"
    },
    "r": {
     "delete_cmd_postfix": ") ",
     "delete_cmd_prefix": "rm(",
     "library": "var_list.r",
     "varRefreshCmd": "cat(var_dic_list()) "
    }
   },
   "types_to_exclude": [
    "module",
    "function",
    "builtin_function_or_method",
    "instance",
    "_Feature"
   ],
   "window_display": false
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
